import datetime

from coin.exchange.base.kr_rest.py_product import PyProduct
import coin.proto.coin_order_enums_pb2 as order_enums
from coin.exchange.kr_rest.product.product_impl import generate_product_from_str2
from coin.support.pta.logic.get_multiplier import get_multiplier


# if we can't consolidate, at least put this logics in same file.
def is_inverse_product(product):
  assert isinstance(product, PyProduct), type(product)
  holder = product.product_holder
  return holder.product_info.is_inverse


def is_inverse(market_type, exchange, symbol, current_datetime=None):
  product = generate_product_from_str2(
      market_type, exchange, None, symbol, current_datetime)
  return is_inverse_product(product)


def get_accounting_currency(market_type, exchange, symbol, current_datetime=None):
  api_version = None
  product = generate_product_from_str2(
      market_type, exchange, api_version, symbol, current_datetime)
  if is_inverse_product(product):
    accounting_currency = product.base.currency
  elif market_type == 'Options' and exchange == 'Deribit':
    accounting_currency = product.base.currency
  elif exchange == 'Bitmex' and product.quote.currency == 'USD':
    accounting_currency = 'BTC'
  elif exchange == 'Gateio' and product.quote.currency == 'USD':
    accounting_currency = 'BTC'
  else:
    accounting_currency = product.quote.currency
  return accounting_currency


def get_futures_multiplier(*args, **kwargs):
  return get_product_multiplier(*args, **kwargs)


def get_product_multiplier(market_type, exchange, symbol, current_datetime=None):
  if market_type in ('Futures', 'Options'):
    api_version = None
    if isinstance(symbol, str):
      product = generate_product_from_str2(market_type, exchange, api_version, symbol, current_datetime)
    else:
      assert isinstance(symbol, PyProduct), type(symbol)
      product = symbol
    multiplier = get_multiplier(product, current_datetime)
  elif market_type in ('Spot', 'Margin'):
    multiplier = 1
  else:
    raise ValueError('Fail to get multiplier. %s %s %s', (market_type, exchange, symbol))
  assert multiplier is not None, (market_type, exchange, symbol)
  return multiplier


def calculate_turnover(
      *, market_type, exchange, symbol, volume, price, current_datetime=None):
  price = 1 / price if is_inverse(market_type, exchange, symbol, current_datetime) \
          else price
  multiplier = get_product_multiplier(market_type, exchange, symbol, current_datetime)
  turnover = price * volume * multiplier
  return turnover


def calculate_turnover_in_quote(
      *, market_type, exchange, symbol, volume, price, current_datetime=None):
  price = 1 if is_inverse(market_type, exchange, symbol, current_datetime) else price
  multiplier = get_product_multiplier(market_type, exchange, symbol, current_datetime)
  turnover = price * volume * multiplier
  return turnover


def calculate_turnover_in_usd(*,
                              market_type,
                              exchange,
                              symbol,
                              volume,
                              turnover,
                              turnover_price_in_usd,
                              current_datetime=None):
  if is_inverse(market_type, exchange, symbol, current_datetime):
    multiplier = get_product_multiplier(market_type, exchange, symbol, current_datetime)
    turnover_mark = multiplier * volume
  else:
    turnover_mark = turnover_price_in_usd * turnover if turnover_price_in_usd \
                    is not None else None
  return turnover_mark


def get_order_sign(order_side):
  buy_order = [
      order_enums.BUY_ORDER, order_enums.BUY_OPEN_ORDER, order_enums.BUY_CLOSE_ORDER]
  sell_order = [
      order_enums.SELL_ORDER, order_enums.SELL_OPEN_ORDER, order_enums.SELL_CLOSE_ORDER]
  if order_side == order_enums.UNKNOWN_ORDER_SIDE:
    sign = 0
  elif order_side in buy_order:
    sign = 1
  elif order_side in sell_order:
    sign = -1
  else:
    raise ValueError('Unknown order side: %s' % order_side)
  return sign
